/**
 * 
 */
package com.autoscript.ext.xmldata.pdm.parse;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.autoscript.ext.xmldata.database.dbmodelext.IndexModelExt;
import com.autoscript.ext.xmldata.dbmodel.ColumnModel;
import com.autoscript.ext.xmldata.dbmodel.DBModel;
import com.autoscript.ext.xmldata.dbmodel.DomainModel;
import com.autoscript.ext.xmldata.dbmodel.IColumnModel;
import com.autoscript.ext.xmldata.dbmodel.IDBModel;
import com.autoscript.ext.xmldata.dbmodel.IDomainModel;
import com.autoscript.ext.xmldata.dbmodel.IIndexModel;
import com.autoscript.ext.xmldata.dbmodel.IKeyModel;
import com.autoscript.ext.xmldata.dbmodel.IReferenceJoinModel;
import com.autoscript.ext.xmldata.dbmodel.IReferenceModel;
import com.autoscript.ext.xmldata.dbmodel.ITableModel;
import com.autoscript.ext.xmldata.dbmodel.KeyModel;
import com.autoscript.ext.xmldata.dbmodel.ReferenceJoinModel;
import com.autoscript.ext.xmldata.dbmodel.ReferenceModel;
import com.autoscript.ext.xmldata.dbmodel.TableModel;
import com.autoscript.ui.helper.FileCtrlUtils;
import com.autoscript.ui.helper.TypeConversionHelper;
import com.autoscript.ui.helper.XMLHelper;
import com.autoscript.ui.model.xml.IXmlAttribute;
import com.autoscript.ui.model.xml.IXmlNode;

//import oracle.net.aso.p;

/**
 * pdm解析器实现 作者:龙色波 日期:2013-10-18
 */
public class PdmParse implements IPdmParse {

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.autoscript.ext.xmldata.pdm.parse.IPdmParse#parse(java.lang.String)
	 */
	@Override
	public IDBModel parse(String pdmFileName) throws Exception {
		String xmlContent;
		xmlContent = FileCtrlUtils.readFileToString(new File(pdmFileName),
				"UTF-8");
		try {
			IXmlNode rootNode = XMLHelper.xml2Model(xmlContent);
			IDBModel pdmModel = new DBModel();
			//获取domain节点列表
			String domainNode = "RootObject.Children.Model.Domains.PhysicalDomain";
			List<IXmlNode> domainNodes = rootNode.getChildNodesByPath(domainNode);
			ArrayList<IDomainModel> domainModels;
			domainModels = new ArrayList<IDomainModel>();
			for(IXmlNode domain:domainNodes) {
				domainModels.add(toDomainModel(domain));
			}
			pdmModel.setDomainModels(domainModels);
			// 获取表节点列表
			// String
			// tableNode="Model.o:RootObject.c:Children.o:Model.c:Tables.o:Table";
			String tableNode = "RootObject.Children.Model.Tables.Table";
			List<IXmlNode> tableNodes = rootNode.getChildNodesByPath(tableNode);
			// 循环解析每个table 模型
			ArrayList<ITableModel> tableModels;
			tableModels = new ArrayList<ITableModel>();
			for (IXmlNode table : tableNodes) {
				tableModels.add(toTableModel(table,domainModels));
			}
			pdmModel.setTableModels(tableModels);
			//获取参考节点列表
			String referenceNode="RootObject.Children.Model.References.Reference";
			List<IXmlNode> referenceNodes = rootNode.getChildNodesByPath(referenceNode);
			//循环解析每个reference 模型
			List<IReferenceModel> referenceModels;
			referenceModels = pdmModel.getReferenceModels();
			for(IXmlNode reference:referenceNodes){
				referenceModels.add(toReferenceModel(reference,tableModels));
			}
			pdmModel.setReferenceModels(referenceModels);
			return pdmModel;
		} catch (Exception e) {
			throw e;
		}
	}
	/**
	 * 	转换domain xml节点为domain 模型
	 * @param domain
	 * @return
	 */
	private IDomainModel toDomainModel(IXmlNode domain) {
		IDomainModel domainModel = new DomainModel();
		//设置表id
		domainModel.setId(domain.getAttributeVal(ID));
		for (IXmlNode child : domain.getChildNodes()) {
			if (NAME.equals(child.getName())) {
				domainModel.setName(child.getValue());
			} else if (CODE.equals(child.getName())) {
				domainModel.setCode(child.getValue());
			} else if (DATATYPE.equals(child.getName())) {
				domainModel.setDataType(child.getValue());
			} else if (LENGTH.equals(child.getName())) {
				domainModel.setLength(Integer.valueOf(child.getValue()));
			}
		}
		return domainModel;
	}
	/**
	 * 将Reference xml节点转为ReferenceModel
	 * @param reference 参考模型
	 * @param tableModels 表格模型列表
	 * @return
	 * @throws Exception 
	 */
	private IReferenceModel toReferenceModel(IXmlNode reference, ArrayList<ITableModel> tableModels) throws Exception {
		IReferenceModel referenceModel = new ReferenceModel();
		for(IXmlNode child:reference.getChildNodes()){
			if(CARDINALITY.equals(child.getName())){
				referenceModel.setCardinality(child.getValue());
			}else if(CHILDTABLE.equals(child.getName())){
				if(child.getChildNodes()!=null && child.getChildNodes().size()>0){
					IXmlNode gradeChild = child.getChildNodes().get(0);
					referenceModel.setChildTable(getTableCodeById(tableModels,gradeChild.getAttributeVal(REF)));
					referenceModel.setChildTableId(gradeChild.getAttributeVal(REF));
				}
			}else if(CODE.equals(child.getName())){
				referenceModel.setCode(child.getValue());
			}else if(ID.equals(child.getName())){
				referenceModel.setId(child.getValue());
			}else if(NAME.equals(child.getName())){
				referenceModel.setName(child.getValue());
			}else if(PARENTTABLE.equals(child.getName())){
				if(child.getChildNodes()!=null && child.getChildNodes().size()>0){
				IXmlNode gradeChild = child.getChildNodes().get(0);
				referenceModel.setParentTable(getTableCodeById(tableModels,gradeChild.getAttributeVal(REF)));
				referenceModel.setParentTableId(gradeChild.getAttributeVal(REF));
				}
			}
		}
		//解析参考连接模型
		referenceModel.setReferenceJoinModels(parseReferenceJoinModel(reference,tableModels,referenceModel));
		return referenceModel;
	}
	/**
	 * 解析参考连接模型
	 * @param reference
	 * @param tableModels
	 * @param referenceModel 参考模型
	 * @return
	 * @throws Exception 
	 */
	private List<IReferenceJoinModel> parseReferenceJoinModel(
			IXmlNode reference, ArrayList<ITableModel> tableModels, IReferenceModel referenceModel) throws Exception {
		String nodeKey="Joins.ReferenceJoin";
		List<IXmlNode> referenceJoins = reference.getChildNodesByPath(nodeKey);
		List<IReferenceJoinModel> referenceJoinModels = new ArrayList<IReferenceJoinModel>();
		for(IXmlNode child:referenceJoins){
			IReferenceJoinModel referenceJoinModel = new ReferenceJoinModel();
			for (IXmlNode grandChild : child.getChildNodes()) {
			if(OBJECT1.equals(grandChild.getName())){
				if(grandChild.getChildNodes()!=null && grandChild.getChildNodes().size()>0){
					IXmlNode greatGrandsonChild = grandChild.getChildNodes().get(0);
					//父表外键名称应该为空
					referenceJoinModel.setParentColumnName(getColumnNameAndUpdateReferenceName(tableModels,referenceModel.getParentTableId(),
							greatGrandsonChild.getAttributeVal(REF),""));
				}
			}else if(OBJECT2.equals(grandChild.getName())){
				if(grandChild.getChildNodes()!=null && grandChild.getChildNodes().size()>0){
					IXmlNode greatGrandsonChild = grandChild.getChildNodes().get(0);
					referenceJoinModel.setChildColumnName(getColumnNameAndUpdateReferenceName(tableModels,referenceModel.getChildTableId(),
							greatGrandsonChild.getAttributeVal(REF),referenceModel.getName()));
				}
			}
			}
			referenceJoinModels.add(referenceJoinModel);
		}
		return referenceJoinModels;
	}
	/**
	 * 根据tableId,ColumnId获取字段名称，同时更新字段关联的外键名称
	 * @param tableModels 表模型
	 * @param tableId 表Id
 	 * @param columnId 字段id
	 * @param referenceName 参考名称(即外键名称) 
	 * @return 返回字段名
	 */
	private String getColumnNameAndUpdateReferenceName(ArrayList<ITableModel> tableModels,
			String tableId, String columnId, String referenceName) {
		for(ITableModel tableModel:tableModels){
			if(tableModel.getId().equals(tableId)){
				for(IColumnModel columnModel:tableModel.getColumnModels()){
					if(columnModel.getId().equals(columnId)){
						columnModel.setReferenceName(referenceName);
						return columnModel.getName();
					}
				}
			}
		}
		return "";
	}
	/**
	 * 获取表编码通过表id
	 * @param tableModels 表模型列表
	 * @param id 表id
	 * @return
	 */
	private String getTableCodeById(ArrayList<ITableModel> tableModels,
			String id) {
		for(ITableModel tableModel:tableModels){
			if(id.equals(tableModel.getId())){
				return tableModel.getCode();
			}
		}
		return null;
	}
	/**
	 * 解析索引
	 * 
	 * @param table
	 * @param tableModel
	 * @param colmap
	 * @throws Exception
	 */
	private void parseIndexModels(IXmlNode table, ITableModel tableModel,
			Map<String, IColumnModel> colmap) throws Exception {
		
		String indexNodeName = "Indexes.Index";
		List<IXmlNode> indexNodes = table.getChildNodesByPath(indexNodeName);
		IIndexModel indexModel;
		List<IIndexModel> indexModes = new ArrayList<IIndexModel>();
		String indexColumnsNodeName = "IndexColumns.IndexColumn.Column.Column";
		for (IXmlNode indexNode : indexNodes) {
			indexModel = new IndexModelExt();
			// 设置索引中文名称和索引英文名
			for (IXmlNode child : indexNode.getChildNodes()) {
				if (NAME.equals(child.getName())) {
					indexModel.setName(child.getValue());
				} else if (CODE.equals(child.getName())) {
					indexModel.setCode(child.getValue());
				} else if(UNIQUE.equals(child.getName())){
					if("1".equals(child.getValue())){
						((IndexModelExt)indexModel).setNonUnique(false);
					}else{
						((IndexModelExt)indexModel).setNonUnique(true);
					}
					
				}
			}
			indexModes.add(indexModel);
			// 获取索引涉及列名
			List<IXmlNode> indexColumnModels = indexNode
					.getChildNodesByPath(indexColumnsNodeName);
			List<String> columnNames = new ArrayList<String>();
			for (IXmlNode child : indexColumnModels) {
				for (IXmlAttribute attr : child.getAttributes()) {
					if (REF.equals(attr.getName())) {
						columnNames.add(colmap.get(attr.getValue()).getCode());
						break;
					}
				}
			}
			indexModel.setColumnNames(columnNames);
		}
		// 设置表的索引模型
		tableModel.setIndexModels(indexModes);
	}

	/**
	 * 解析列
	 * 
	 * @param table
	 * @param tableModel
	 * @param colmap
	 * @param domainModels 
	 * @throws Exception
	 */
	private void parseColumns(IXmlNode table, ITableModel tableModel,
			Map<String, IColumnModel> colmap, ArrayList<IDomainModel> domainModels) throws Exception {
		List<IXmlNode> columnNodes = table
				.getChildNodesByPath("Columns.Column");
		// 循环解析列模型
		List<IColumnModel> columnModels = new ArrayList<IColumnModel>();

		for (IXmlNode child : columnNodes) {
			IColumnModel columnModel = new ColumnModel();
			//设置列id属性
			columnModel.setId(child.getAttributeVal(ID));
			for (IXmlNode grandChild : child.getChildNodes()) {
				if (NAME.equals(grandChild.getName())) {
					columnModel.setName(grandChild.getValue());
				} else if (CODE.equals(grandChild.getName())) {
					columnModel.setCode(grandChild.getValue());
				} else if (DATATYPE.equals(grandChild.getName())) {
					columnModel.setDataType(grandChild.getValue());
					//截断括号
					int pos = columnModel.getDataType().indexOf(LEFT_BRACKET);
					if(pos>=0){
						columnModel.setDataType(columnModel.getDataType().substring(0, pos));
					}
				} else if (MANDATORY.equals(grandChild.getName())||OLD_MANDATORY.equals(grandChild.getName())) {
					columnModel.setMandatory("1".equals(grandChild.getValue()));
				} else if (LENGTH.equals(grandChild.getName())) {
					try {
						columnModel.setLength(TypeConversionHelper
								.StringToInt(grandChild.getValue()));
					} catch (Exception e) {
						columnModel.setLength(0);
					}
				} else if (PRECISION.equals(grandChild.getName())) {
					try {
						columnModel.setPrecision(TypeConversionHelper
								.StringToInt(grandChild.getValue()));
					} catch (Exception e) {
						columnModel.setPrecision(0);
					}
				} else if(COMMENT.equals(grandChild.getName())){
					columnModel.setComment(grandChild.getValue());
				} else if(DOMAIN.equals(grandChild.getName())) {
					columnModel.setDomain(getDomainInColumnModel(grandChild,domainModels));
				}
			}
			// 获取属性值id
			for (IXmlAttribute attr : child.getAttributes()) {
				if (ID.equals(attr.getName())) {
					// 放入map 方便后面搜索
					colmap.put(attr.getValue(), columnModel);
					break;
				}
			}
			// 加入列列表
			columnModels.add(columnModel);
			// 设置到表模型
			tableModel.setColumnModels(columnModels);
		}
	}
	/**
	 * 获取列的domain名称
	 * @param parentNode
	 * @param domainModels
	 * @return
	 */
	private String getDomainInColumnModel(IXmlNode parentNode, ArrayList<IDomainModel> domainModels) {
		
		for(IXmlNode childNode:parentNode.getChildNodes()) {
			String domainId = childNode.getAttributeVal(REF);
			for(IDomainModel domainModel:domainModels) {
				if(domainModel.getId().equals(domainId)) {
					return domainModel.getName();
				}
			}
		}
		return null;
	}
	/**
	 * 解析主键
	 * 
	 * @param table
	 * @param tableModel
	 * @param colmap
	 * @throws Exception
	 */
	private void parseKeys(IXmlNode table, ITableModel tableModel,
			Map<String, IColumnModel> colmap) throws Exception {
		String keyNodeName = "Keys.Key";
		IXmlNode keyNode;
		IXmlNode keyColumnsNode = null;
		List<IXmlNode> tmpNodes = table.getChildNodesByPath(keyNodeName);
		List<String> keys = new ArrayList<String>();
		IKeyModel keyModel;
		// 如果有主键
		if (tmpNodes.size() > 0) {
			keyNode = tmpNodes.get(0);
			keyModel = new KeyModel();
			// 设置name和code
			for (IXmlNode child : keyNode.getChildNodes()) {
				if (NAME.equals(child.getName())) {
					keyModel.setName(child.getValue());
				} else if (CODE.equals(child.getName())) {
					keyModel.setCode(child.getValue());
				}
			}
			for (IXmlNode keyChildNode : keyNode.getChildNodes()) {
				if (KEYCOLUMNS.equals(keyChildNode.getName())) {
					keyColumnsNode = keyChildNode;
					break;
				}
			}
			if (keyColumnsNode != null) {
				for (IXmlNode childNode : keyColumnsNode.getChildNodes()) {
					if (O_COLUMN.equals(childNode.getName())) {
						for (IXmlAttribute attr : childNode.getAttributes()) {
							if (REF.equals(attr.getName())) {
								keys.add(colmap.get(attr.getValue()).getCode());
							}
						}
					}
				}
			}
			// 设置主键到表模型
			if (keys.size() > 0) {
				keyModel.setColumns(keys);
				tableModel.setKey(keyModel);
			}
		}
	}
	/**
	 * 将Table xml节点转换为 TableModel
	 * 
	 * @param table
	 * @param domainModels
	 * @return
	 * @throws Exception
	 */
	private ITableModel toTableModel(IXmlNode table,ArrayList<IDomainModel> domainModels) throws Exception {
		ITableModel tableModel = new TableModel();
		//设置表id
		tableModel.setId(table.getAttributeVal(ID));
		for (IXmlNode child : table.getChildNodes()) {
			if (NAME.equals(child.getName())) {
				tableModel.setName(child.getValue());
			} else if (CODE.equals(child.getName())) {
				tableModel.setCode(child.getValue());
			} else if (COMMENT.equals(child.getName())) {
				tableModel.setComment(child.getValue());
			}
		}
		// 获取列节点列表
		Map<String, IColumnModel> colmap = new HashMap<String, IColumnModel>();
		// 解析列
		parseColumns(table, tableModel, colmap,domainModels);
		// 解析主键
		parseKeys(table, tableModel, colmap);
		// 解析索引
		parseIndexModels(table, tableModel, colmap);
		return tableModel;
	}
	@Override
	public IDBModel parse(byte[] bytes) throws Exception {
		String xmlContent;
		xmlContent = new String(bytes,"UTF-8");
		try {
			IXmlNode rootNode = XMLHelper.xml2Model(xmlContent);
			IDBModel pdmModel = new DBModel();
			//获取domain节点列表
			String domainNode = "RootObject.Children.Model.Domains.PhysicalDomain";
			List<IXmlNode> domainNodes = rootNode.getChildNodesByPath(domainNode);
			ArrayList<IDomainModel> domainModels;
			domainModels = new ArrayList<IDomainModel>();
			for(IXmlNode domain:domainNodes) {
				domainModels.add(toDomainModel(domain));
			}
			pdmModel.setDomainModels(domainModels);
			// 获取表节点列表
			// String
			// tableNode="Model.o:RootObject.c:Children.o:Model.c:Tables.o:Table";
			String tableNode = "RootObject.Children.Model.Tables.Table";
			List<IXmlNode> tableNodes = rootNode.getChildNodesByPath(tableNode);
			// 循环解析每个table 模型
			ArrayList<ITableModel> tableModels;
			tableModels = new ArrayList<ITableModel>();
			for (IXmlNode table : tableNodes) {
				tableModels.add(toTableModel(table,domainModels));
			}
			pdmModel.setTableModels(tableModels);
			//获取参考节点列表
			String referenceNode="RootObject.Children.Model.References.Reference";
			List<IXmlNode> referenceNodes = rootNode.getChildNodesByPath(referenceNode);
			//循环解析每个reference 模型
			List<IReferenceModel> referenceModels;
			referenceModels = pdmModel.getReferenceModels();
			for(IXmlNode reference:referenceNodes){
				referenceModels.add(toReferenceModel(reference,tableModels));
			}
			pdmModel.setReferenceModels(referenceModels);
			return pdmModel;
		} catch (Exception e) {
			throw e;
		}
	}

}
